package
{
	import com.greensock.TweenLite;
	import com.greensock.easing.Bounce;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;

	// 1 - 1:30 start
	// 9:15 - 10:25
	// 10/20/12 : 9:30 - 11:00
	
	public class Game
	{
		public static var instance:Game;
		public static var stage:Stage;
		public static const PPS:int = 50; // Pixels per square
		public static const DIMENSIONS:Point = new Point(10,10);
		public var gameObjects:Vector.<GameObject> = new Vector.<GameObject>;
		private var display:Sprite = new Sprite();
		private var m_hud:Hud;

		public static var config:Config;
		
		
		
		public static const GAME_STATE_START_PLAYING:int = 0;
		public static const GAME_STATE_PLAYING:int = 0;
		public static const GAME_STATE_START_EVALUATION:int = 1;
		public static const GAME_STATE_EVALUATING:int = 2;
		public static const GAME_STATE_PLACE_ITEM_COOLDOWN:int = 3;
		
		public var gameState:int = 0;
		
		
		public function Game(parentDisplay:Sprite)
		{
			ImageManager.startLoad(onImageLoadComplete);
			parentDisplay.addChild(display);
			
			var bg:DisplayObject = Util.getRectSprite(PPS*DIMENSIONS.x, PPS*DIMENSIONS.y, 0xEEEEEE,1);
			var grid:Sprite = Util.getGridSprite(PPS, DIMENSIONS);
			display.addChild(bg);
			display.addChild(grid);
			
		}
		
		private function onImageLoadComplete():void{			
			display.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			display.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			display.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);			
			
			setupTestGame();			
		}
		
		
		private var m_dragHelper:GMDragHelper = new GMDragHelper();
		
		private function onMouseMove(me:MouseEvent):void{
			m_dragHelper.onMouseMove(me);
			if(m_dragHelper.isDragging()){
				trace("is dragging");
			} else {
				m_gameModes[0].onMouseMove(me);	
			}
			
		}		
		
		private function onMouseDown(me:MouseEvent):void{
			m_dragHelper.onMouseDown(me);
			if(!m_dragHelper.isDragging()){
				m_gameModes[0].onMouseDown(me);
			}
		}
		
		private function onMouseUp(me:MouseEvent):void{
			m_dragHelper.onMouseUp(me);
			if(!m_dragHelper.isDragging()){
				m_gameModes[0].onMouseUp(me);
			}
		}
		
		private var m_selectableObjects:Vector.<ISelectable> = new Vector.<ISelectable>;
		
		public function findSelectedObject(mousePosition:Point):ISelectable{
			var gameObjects:Vector.<ISelectable> = new Vector.<ISelectable>;
			var stores:Vector.<ISelectable> = new Vector.<ISelectable>
			var selected:ISelectable;
			var i:int, length:int;
			
			for(i = 0, length = m_selectableObjects.length; i < length; i++){
				if(m_selectableObjects[i].hitTestPoint(mousePosition)){
					switch(true){
						case (m_selectableObjects[i] is GameObject):
							gameObjects.push(m_selectableObjects[i]);
							break;
					}
				}
			}
			
			if(gameObjects.length){
				selected = gameObjects[0];
			} else if(stores.length){
				selected = stores[0];
			}
			
			return selected;
		}
		
		private var m_paused:Boolean = false;
		public function pause():void{
			m_paused  = true;
		}
		
		public function resume():void{
			m_paused = false;
		}
		
		
		
		
		private function setupTestGame():void{
			
			setupNextItem();
			m_hud = new Hud();
			display.parent.addChild(m_hud.display);
			m_hud.init();
			m_hud.doneButton.addEventListener(MouseEvent.CLICK, onHudDoneClick);
			m_gameModes.push(new GMDefault(display));
		}
		
		private function onHudDoneClick(me:MouseEvent):void{
			leaveGameMode();
		}
		private var m_evaluationFinsihed:Boolean = true;
		
		public function changeGameState(gameState:int):void{
			this.gameState = gameState;
		}
		
		public function step(delta:int):void{
			var i:int, j:int, il:int;

			switch(gameState){
				case GAME_STATE_START_EVALUATION:
					evaluateBoard();
					break;
				case GAME_STATE_EVALUATING:
					var stillMoving:Boolean = false;
					for(i = 0, il = gameObjects.length; i < il; i++){
						gameObjects[i].step(delta);
						stillMoving = stillMoving || gameObjects[i].isMoving();	
					}						
					
					for(i = 0; i < gameObjects.length; i++){
						var go:GameObject = gameObjects[i];
						if(!go.isMoving() && !go.inPlay){
							go.display.parent.removeChild(go.display);
							gameObjects.splice(gameObjects.indexOf(go),1);
						}
					}
					
					if(!stillMoving){
						if(!m_evaluationFinsihed ){
							changeGameState(GAME_STATE_START_EVALUATION);
						}
					}		
					break;
				case GAME_STATE_PLAYING:
					break;
			}
		}
		
		
		public function leaveGameMode():void{
			m_hud.hideDoneButton();
			var gameMode:IGameMode = m_gameModes.shift();
			gameMode.cleanup();
		}
		
		public function stage2game(stagePoint:Point):Point{
			return stagePoint.subtract(new Point(display.x, display.y));
		}
		
		private var m_gameModes:Vector.<IGameMode> = new Vector.<IGameMode>;
		public function enterGameMode(gameMode:IGameMode):void{
			//m_hud.showDoneButton();
			m_gameModes.unshift(gameMode);
		}
		
		public var nextItem:GameObject;
		
		public function overrideNextItem(overrideItem:GameObject):void{
			nextItem.display.parent.removeChild(nextItem.display);
			nextItem = overrideItem;
			(m_gameModes[0] as GMDefault).overrideNextItem();
		}
		
		public function setupNextItem():void{
			
			nextItem = new GameObject();
			nextItem.type = GameObject.getRandomType();
			nextItem.level = 1;
			
			nextItem.updateDisplay();
		}
		public function getNextItem():GameObject{
			return this.nextItem;
		}
		
		private function putGameObjectIntoPlay(gameObject:GameObject):void{
			gameObject.inPlay = true;
			gameObjects.push(gameObject);
			gameObject.updateDisplay();
			display.addChild(gameObject.display);
		}

		
		public function placeNextItem():void{
			putGameObjectIntoPlay(nextItem);
			Util.scale(nextItem.display, 0, 1, .25);
			setupNextItem();
			changeGameState(GAME_STATE_START_EVALUATION);
		}
		
		private function matchSetTransfer(source:MatchSet, dest:MatchSet):void{
			for(var i:int = 0, l:int = source.gameObjects.length; i < l; i++){
				dest.add(source.gameObjects[i]);
			}
		}
		
		public function hasObject(go:GameObject):Boolean{
			return (gameObjects.indexOf(go) != -1);
		}
		
		public function getUnpopulatedSpaces():Vector.<Point>{
			var spaces:Object = new Object();
			var length:int;
			for(var i:int = 0; i < DIMENSIONS.x; i++){
				for(var j:int = 0; j < DIMENSIONS.y; j++){
					spaces[i+","+j] = new Point(i,j);
				}
			}
			
			for(i = 0, length = gameObjects.length; i < length; i++){
				delete spaces[String(gameObjects[i].nextLocation.x) + "," + String(gameObjects[i].nextLocation.y)];
			}
			
			var unpopulated:Vector.<Point> = new Vector.<Point>
			for each(var space:Point in spaces){
				unpopulated.push(space);
			}
			
			return unpopulated;
		}

		private function evaluateBoard():void{
			var matchSet:MatchSet;
			var sets:Vector.<MatchSet> = new Vector.<MatchSet>;
			var gameObject:GameObject ;
			
			var setsByGameObject:Dictionary = new Dictionary(true);
			
			m_evaluationFinsihed = false;
			changeGameState(GAME_STATE_EVALUATING);
			var unpopulatedSpaces:Vector.<Point> = getUnpopulatedSpaces();
			var i:int, il:int, j:int, jl:int;
			
			for(i = 0, il = gameObjects.length; i < il; i++){
				gameObject = gameObjects[i];
				if(!gameObject.inPlay){
					continue;
				}
				
				var matchSetFound:Boolean = false;
				for(j = 0, jl = sets.length; j < jl; j++){
					matchSet = sets[j];
					if(matchSet.test(gameObject)){
						matchSet.convergencePoint = gameObject.nextLocation.clone();
						if(matchSetFound){ // This is already in another matched set
							var otherMatchSet:MatchSet = setsByGameObject[gameObject];
							matchSetTransfer(matchSet,otherMatchSet);
							matchSet.markForDestroy = true;
							
						} else {
							setsByGameObject[gameObject ] = matchSet;
							matchSet.add(gameObject);
							matchSetFound = true;
							//Util.glowMatchSet(matchSet, Math.random()*0xffffff);							
						}
					}
				}
				
				for(j = 0; j < sets.length; j++){
					matchSet = sets[j];
					if(matchSet.markForDestroy){
						sets.splice(sets.indexOf(matchSet),1);
					}
				}				
				
				if(!matchSetFound){
					matchSet = new MatchSet();
					matchSet.add(gameObject);
					sets.push(matchSet);
				}
			}
			
			var numProcessableMatchSets:int = 0;
			for(i = 0, il = sets.length; i < il; i++){
				matchSet = sets[i];
				if(matchSet.gameObjects.length >= 3){
					var nextPoint:Point = matchSet.convergencePoint;
					var newItem:GameObject = matchSet.createMatchedItem();
					newItem.forceLocation(nextPoint);
					putGameObjectIntoPlay(newItem);	
					
					for(j = 0; j < matchSet.gameObjects.length; j++){
						gameObject = matchSet.gameObjects[j];
						gameObject.nextLocation = nextPoint;
						gameObject.inPlay = false;
					}					
					
				
					
					numProcessableMatchSets++;
				}
			}
			
			if(numProcessableMatchSets == 0){
				m_evaluationFinsihed = true;
			}
		
		}
	}
}